package com.rbac.modules.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rbac.modules.system.dto.DeptDTO;
import com.rbac.modules.system.dto.DeptQuery;
import com.rbac.modules.system.entity.SysDept;
import com.rbac.modules.system.mapper.SysDeptMapper;
import com.rbac.modules.system.service.SysDeptService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {

    @Override
    public Page<SysDept> page(DeptQuery query) {
        LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(query.getDeptName()), SysDept::getDeptName, query.getDeptName())
                .like(StringUtils.hasText(query.getLeader()), SysDept::getLeader, query.getLeader())
                .eq(query.getStatus() != null, SysDept::getStatus, query.getStatus())
                .orderByAsc(SysDept::getSort);

        return this.page(new Page<>(query.getCurrent(), query.getSize()), wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(DeptDTO deptDTO) {
        // 检查部门名称是否存在
        if (checkDeptNameExists(deptDTO.getDeptName(), deptDTO.getParentId(), null)) {
            throw new RuntimeException("部门名称已存在");
        }

        SysDept dept = new SysDept();
        BeanUtils.copyProperties(deptDTO, dept);
        this.save(dept);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(DeptDTO deptDTO) {
        // 检查部门名称是否存在
        if (checkDeptNameExists(deptDTO.getDeptName(), deptDTO.getParentId(), deptDTO.getId())) {
            throw new RuntimeException("部门名称已存在");
        }

        SysDept dept = new SysDept();
        BeanUtils.copyProperties(deptDTO, dept);
        this.updateById(dept);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long[] ids) {
        // 检查是否存在子部门
        for (Long id : ids) {
            List<Long> childrenIds = this.getChildrenIds(id);
            if (!childrenIds.isEmpty()) {
                throw new RuntimeException("存在子部门，无法删除");
            }
        }
        this.removeByIds(List.of(ids));
    }

    @Override
    public List<SysDept> tree() {
        // 获取所有部门
        List<SysDept> allDepts = this.list();
        
        // 构建树形结构
        Map<Long, List<SysDept>> parentMap = allDepts.stream()
                .collect(Collectors.groupingBy(SysDept::getParentId));
        
        return buildTree(0L, parentMap);
    }

    @Override
    public List<Long> getChildrenIds(Long parentId) {
        return baseMapper.selectChildrenIds(parentId);
    }

    @Override
    public List<Long> getAllChildrenIds(Long parentId) {
        return baseMapper.selectAllChildrenIds(parentId);
    }

    @Override
    public boolean checkDeptNameExists(String deptName, Long parentId, Long excludeId) {
        LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDept::getDeptName, deptName)
                .eq(SysDept::getParentId, parentId)
                .ne(excludeId != null, SysDept::getId, excludeId);
        return this.count(wrapper) > 0;
    }

    private List<SysDept> buildTree(Long parentId, Map<Long, List<SysDept>> parentMap) {
        List<SysDept> children = parentMap.get(parentId);
        if (children == null) {
            return new ArrayList<>();
        }
        
        // 对子节点进行排序
        children.sort((a, b) -> a.getSort() - b.getSort());
        
        // 递归处理每个子节点
        for (SysDept child : children) {
            List<SysDept> grandChildren = buildTree(child.getId(), parentMap);
            if (!grandChildren.isEmpty()) {
                child.setChildren(grandChildren);
            }
        }
        
        return children;
    }
} 